import sys
import os
import json
import uuid
import datetime
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from mpl_toolkits.mplot3d import Axes3D
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QSplitter, 
    QTabWidget, QGroupBox, QLabel, QLineEdit, QPushButton, QComboBox, 
    QTextEdit, QListWidget, QScrollArea, QFileDialog, QMessageBox, QGridLayout,
    QSizePolicy, QProgressBar, QStyleFactory, QFrame, QStatusBar
)
from PyQt6.QtGui import QIcon, QFont, QPalette, QColor, QPixmap, QImage
from PyQt6.QtCore import Qt, QSize, QTimer
import requests
import matplotlib
matplotlib.use('Qt5Agg')

# 环境参数类
class EnvironmentParameters:
    def __init__(self):
        self.params = {
            "temperature": 25.0,
            "humidity": 50.0,
            "wind_speed": 5.0,
            "wind_direction": 180.0,
            "soil_moisture": 30.0,
            "vegetation_density": 0.7,
            "terrain_slope": 15.0,
            "terrain_aspect": 45.0,
            "elevation": 500.0,
            "fuel_load": 0.8,
            "precipitation": 20.0,
            "solar_radiation": 800.0,
            "canopy_cover": 60.0,
            "fuel_moisture": 15.0,
            "fire_history": 0.3,
            "human_activity": 0.4,
            "river_discharge": 150.0,
            "snow_water_equivalent": 25.0,
            "groundwater_level": 10.0,
            "drainage_capacity": 0.6,
            "impervious_surface": 30.0,
            "catchment_area": 100.0
        }
        self.simulation_type = "wildfire"
        self.name = "未命名模拟"
        self.description = ""
        self.uuid = ""
        self.timestamp = ""
    
    def to_dict(self):
        return {
            "simulation_type": self.simulation_type,
            "name": self.name,
            "description": self.description,
            "uuid": self.uuid,
            "timestamp": self.timestamp,
            "parameters": self.params.copy()
        }
    
    def from_dict(self, data):
        self.simulation_type = data.get("simulation_type", "wildfire")
        self.name = data.get("name", "未命名模拟")
        self.description = data.get("description", "")
        self.uuid = data.get("uuid", "")
        self.timestamp = data.get("timestamp", "")
        self.params = data.get("parameters", self.params.copy())

# 火灾模型
class ForestFireModel:
    def __init__(self, params):
        self.params = params
        self.grid_size = 128
        self.risk_map = np.zeros((self.grid_size, self.grid_size))
        self.terrain = np.zeros((self.grid_size, self.grid_size))
        self.critical_zones = []
        self.results = {}
    
    def calculate(self):
        # 生成地形
        x = np.linspace(0, 100, self.grid_size)
        y = np.linspace(0, 100, self.grid_size)
        X, Y = np.meshgrid(x, y)
        
        # 创建地形 - 添加山脉和山谷
        self.terrain = (
            np.sin(X/10) * 30 + 
            np.cos(Y/15) * 25 + 
            np.sin(X/5 + Y/5) * 15 +
            self.params['elevation']
        )
        
        # 计算基础风险
        temp_factor = np.maximum(0, (self.params['temperature'] - 25) / 20 + 1)
        humidity_factor = 1 - self.params['humidity'] / 100
        fuel_factor = self.params['fuel_load'] ** 1.5
        moisture_factor = 1 - self.params['fuel_moisture'] / 40
        history_factor = 1 + self.params['fire_history'] * 0.5
        human_factor = 1 + self.params['human_activity'] * 0.4
        
        base_risk = temp_factor * humidity_factor * fuel_factor * moisture_factor * history_factor * human_factor
        
        # 应用地形影响
        slope_risk = np.minimum(2, np.maximum(1, (self.terrain - 400) / 200))
        self.risk_map = base_risk * slope_risk
        
        # 风向影响
        wind_dir_rad = np.radians(self.params['wind_direction'])
        wind_speed_factor = np.minimum(2, self.params['wind_speed'] / 15)
        
        for i in range(1, self.grid_size-1):
            for j in range(1, self.grid_size-1):
                slope_x = (self.terrain[i+1, j] - self.terrain[i-1, j]) / 2
                slope_y = (self.terrain[i, j+1] - self.terrain[i, j-1]) / 2
                slope_angle = np.arctan2(slope_y, slope_x)
                
                angle_diff = np.abs(slope_angle - wind_dir_rad)
                wind_effect = 1 + wind_speed_factor * np.cos(angle_diff) * 0.8
                
                self.risk_map[i, j] *= wind_effect
                
                # 邻居影响
                neighbor_effect = 0
                for di in [-1, 0, 1]:
                    for dj in [-1, 0, 1]:
                        if di == 0 and dj == 0:
                            continue
                        neighbor_effect += self.risk_map[i+di, j+dj] * 0.05
                self.risk_map[i, j] += neighbor_effect
        
        # 计算整体结果
        overall_risk = np.mean(self.risk_map)
        spread_prob = min(0.95, overall_risk * 1.2)
        
        # 确定风险等级
        if overall_risk < 0.3:
            risk_level = "低风险"
        elif overall_risk < 0.6:
            risk_level = "中风险"
        elif overall_risk < 0.8:
            risk_level = "高风险"
        else:
            risk_level = "极高风险"
        
        # 识别关键区域
        self.critical_zones = []
        threshold = np.percentile(self.risk_map, 90)
        for i in range(0, self.grid_size, 5):
            for j in range(0, self.grid_size, 5):
                if self.risk_map[i, j] > threshold:
                    self.critical_zones.append((i, j, self.risk_map[i, j]))
        
        # 保存结果
        self.results = {
            "overall_risk": overall_risk,
            "spread_probability": spread_prob,
            "risk_level": risk_level,
            "critical_zones": self.critical_zones,
            "risk_map": self.risk_map.tolist(),
            "terrain": self.terrain.tolist()
        }
        
        return self.results

# 洪水模型
class FloodDroughtModel:
    def __init__(self, params):
        self.params = params
        self.grid_size = 128
        self.water_map = np.zeros((self.grid_size, self.grid_size))
        self.flood_map = np.zeros((self.grid_size, self.grid_size))
        self.drought_map = np.zeros((self.grid_size, self.grid_size))
        self.terrain = np.zeros((self.grid_size, self.grid_size))
        self.results = {}
    
    def calculate(self):
        # 生成地形
        x = np.linspace(0, 100, self.grid_size)
        y = np.linspace(0, 100, self.grid_size)
        X, Y = np.meshgrid(x, y)
        
        # 创建地形 - 添加河流和山谷
        river = np.exp(-((X-50)**2 + (Y-20)**2)/500) * 40
        valley = np.sin(X/12) * 15 + np.cos(Y/10) * 10
        
        self.terrain = (
            np.sin(X/10) * 25 + 
            np.cos(Y/8) * 20 + 
            valley - river +
            self.params['terrain_elevation']
        )
        
        # 计算水平衡
        precipitation_volume = self.params['precipitation'] * self.params['catchment_area']
        evaporation_loss = self.params['evaporation_rate'] * 30 * self.params['catchment_area'] * 0.5
        river_contribution = self.params['river_discharge'] * 30 * 0.8
        water_balance = precipitation_volume + river_contribution - evaporation_loss
        
        # 计算水分布
        base_water = water_balance / (self.params['catchment_area'] * 100) * 1000
        
        for i in range(self.grid_size):
            for j in range(self.grid_size):
                soil_capacity = 50 * (1 - self.params['impervious_surface']/100)
                elevation_factor = 1 - (self.terrain[i, j] - np.min(self.terrain)) / (np.max(self.terrain) - np.min(self.terrain))
                
                water_content = base_water * elevation_factor
                
                if water_content > soil_capacity:
                    self.flood_map[i, j] = water_content - soil_capacity
                    self.drought_map[i, j] = 0
                else:
                    self.flood_map[i, j] = 0
                    self.drought_map[i, j] = soil_capacity - water_content
        
        # 计算洪水风险
        flood_risk = np.sum(self.flood_map) / (self.grid_size * self.grid_size * 10)
        flood_prob = min(0.95, flood_risk * 3)
        
        # 计算干旱风险
        drought_risk = np.sum(self.drought_map) / (self.grid_size * self.grid_size * 10)
        drought_prob = min(0.95, drought_risk * 2)
        
        # 确定风险等级
        if flood_risk < 0.2:
            flood_level = "低风险"
        elif flood_risk < 0.4:
            flood_level = "中风险"
        elif flood_risk < 0.6:
            flood_level = "高风险"
        else:
            flood_level = "极高风险"
        
        if drought_risk < 0.2:
            drought_level = "低风险"
        elif drought_risk < 0.4:
            drought_level = "中风险"
        elif drought_risk < 0.6:
            drought_level = "高风险"
        else:
            drought_level = "极高风险"
        
        # 识别关键区域
        flood_zones = []
        drought_zones = []
        
        flood_threshold = np.percentile(self.flood_map, 90)
        drought_threshold = np.percentile(self.drought_map, 90)
        
        for i in range(0, self.grid_size, 5):
            for j in range(0, self.grid_size, 5):
                if self.flood_map[i, j] > flood_threshold:
                    flood_zones.append((i, j, self.flood_map[i, j]))
                if self.drought_map[i, j] > drought_threshold:
                    drought_zones.append((i, j, self.drought_map[i, j]))
        
        # 保存结果
        self.results = {
            "flood_risk": flood_risk,
            "drought_risk": drought_risk,
            "flood_probability": flood_prob,
            "drought_probability": drought_prob,
            "flood_level": flood_level,
            "drought_level": drought_level,
            "water_balance": water_balance,
            "flood_zones": flood_zones,
            "drought_zones": drought_zones,
            "flood_map": self.flood_map.tolist(),
            "drought_map": self.drought_map.tolist(),
            "terrain": self.terrain.tolist()
        }
        
        return self.results

# 3D可视化画布
class ThreeDCanvas(FigureCanvas):
    def __init__(self, parent=None, width=8, height=6, dpi=100):
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        super().__init__(self.fig)
        self.setParent(parent)
        self.ax = self.fig.add_subplot(111, projection='3d')
        self.ax.set_position([0, 0, 1, 1])
        self.data = None
        self.simulation_type = ""
        
    def plot_terrain(self, terrain, risk_map, sim_type):
        self.simulation_type = sim_type
        self.data = (terrain, risk_map)
        
        self.ax.clear()
        x = np.arange(terrain.shape[1])
        y = np.arange(terrain.shape[0])
        X, Y = np.meshgrid(x, y)
        Z = terrain
        
        # 创建表面图
        surf = self.ax.plot_surface(X, Y, Z, cmap='terrain', alpha=0.7, 
                                  linewidth=0, antialiased=True)
        
        # 添加风险覆盖
        if sim_type == "wildfire":
            risk_normalized = risk_map / np.max(risk_map)
            colors = plt.cm.RdYlGn_r(1 - risk_normalized)
            self.ax.plot_surface(X, Y, Z + 0.1, facecolors=colors, alpha=0.6)
            
            # 添加关键点
            max_risk = np.max(risk_map)
            for i in range(0, terrain.shape[0], 5):
                for j in range(0, terrain.shape[1], 5):
                    if risk_map[i, j] > max_risk * 0.8:
                        self.ax.scatter(j, i, terrain[i, j] + 1, c='red', s=20, marker='o')
            
            self.ax.set_title("火灾风险地形图", fontsize=12)
        else:
            # 洪水/干旱可视化
            flood_mask = risk_map > np.percentile(risk_map, 75)
            drought_mask = risk_map < np.percentile(risk_map, 25)
            
            if np.any(flood_mask):
                self.ax.scatter(X[flood_mask], Y[flood_mask], Z[flood_mask] + 0.5, 
                              c='blue', s=5, alpha=0.6, label='洪水风险区')
            
            if np.any(drought_mask):
                self.ax.scatter(X[drought_mask], Y[drought_mask], Z[drought_mask] + 0.5, 
                              c='brown', s=5, alpha=0.6, label='干旱风险区')
            
            self.ax.set_title("洪水/干旱风险地形图", fontsize=12)
        
        self.ax.set_xlabel('X')
        self.ax.set_ylabel('Y')
        self.ax.set_zlabel('高程')
        self.fig.colorbar(surf, shrink=0.5, aspect=5)
        self.draw()
    
    def save_image(self, filename):
        if self.data:
            terrain, risk_map = self.data
            self.plot_terrain(terrain, risk_map, self.simulation_type)
            self.fig.savefig(filename, dpi=150, bbox_inches='tight')

# 2D可视化画布
class TwoDCanvas(FigureCanvas):
    def __init__(self, parent=None, width=8, height=6, dpi=100):
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        super().__init__(self.fig)
        self.setParent(parent)
        self.ax = self.fig.add_subplot(111)
        self.data = None
        self.simulation_type = ""
        
    def plot_map(self, data, sim_type, title=""):
        self.simulation_type = sim_type
        self.data = data
        
        self.ax.clear()
        
        if sim_type == "wildfire":
            # 火灾风险热力图
            im = self.ax.imshow(data, cmap='RdYlGn_r', origin='lower', 
                               extent=[0, 100, 0, 100], vmin=0, vmax=1)
            self.ax.set_title(f"火灾风险热力图 - {title}", fontsize=12)
            self.fig.colorbar(im, label='风险指数')
        else:
            # 洪水/干旱风险图
            flood_map = data[0]
            drought_map = data[1]
            
            flood_mask = flood_map > 0
            drought_mask = drought_map > 0
            
            if np.any(flood_mask):
                self.ax.contourf(flood_map, levels=10, cmap='Blues', alpha=0.5, 
                                extent=[0, 100, 0, 100])
            
            if np.any(drought_mask):
                self.ax.contourf(drought_map, levels=10, cmap='YlOrBr', alpha=0.5, 
                                extent=[0, 100, 0, 100])
            
            self.ax.set_title(f"洪水(蓝)与干旱(棕)风险图 - {title}", fontsize=12)
        
        self.ax.set_xlabel('X (km)')
        self.ax.set_ylabel('Y (km)')
        self.ax.grid(True, linestyle='--', alpha=0.3)
        self.draw()
    
    def save_image(self, filename):
        if self.data:
            if self.simulation_type == "wildfire":
                self.plot_map(self.data, self.simulation_type)
            else:
                self.plot_map(self.data, self.simulation_type)
            self.fig.savefig(filename, dpi=150, bbox_inches='tight')

# AI分析助手
class AIAssistant:
    def __init__(self, api_key=None):
        self.api_key = api_key
        self.base_url = "https://api.deepseek.com/v1/chat/completions"
        self.model = "deepseek-chat"
        self.history = []
    
    def get_advice(self, params, results):
        if not self.api_key:
            return "未设置API密钥，无法获取AI建议"
        
        # 构建提示
        prompt = (
            f"作为生态保护专家，请为以下环境模拟结果提供专业建议：\n\n"
            f"模拟类型: {params['simulation_type']}\n"
            f"模拟名称: {params['name']}\n\n"
        )
        
        if params['simulation_type'] == "wildfire":
            prompt += (
                f"火灾风险分析结果：\n"
                f"综合风险指数: {results['overall_risk']:.2f}\n"
                f"蔓延概率: {results['spread_probability']:.2f}\n"
                f"风险等级: {results['risk_level']}\n\n"
                f"环境参数：\n"
                f"温度: {params['parameters']['temperature']}°C, "
                f"湿度: {params['parameters']['humidity']}%, "
                f"风速: {params['parameters']['wind_speed']}m/s, "
                f"植被密度: {params['parameters']['vegetation_density']}\n\n"
                "请提供具体的生态保护建议、预防措施和恢复方案，使用专业术语但保持建议实用可操作。"
            )
        else:
            prompt += (
                f"洪水/干旱分析结果：\n"
                f"洪水风险: {results['flood_risk']:.2f} ({results['flood_level']})\n"
                f"干旱风险: {results['drought_risk']:.2f} ({results['drought_level']})\n"
                f"水平衡: {results['water_balance']:.2f} m³\n\n"
                f"环境参数：\n"
                f"降水量: {params['parameters']['precipitation']}mm, "
                f"温度: {params['parameters']['temperature']}°C, "
                f"河流流量: {params['parameters']['river_discharge']}m³/s, "
                f"集水区面积: {params['parameters']['catchment_area']}km²\n\n"
                "请提供具体的水资源管理建议、防洪抗旱措施和生态恢复方案，使用专业术语但保持建议实用可操作。"
            )
        
        # 构建请求
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        data = {
            "model": self.model,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": 0.7,
            "max_tokens": 1000
        }
        
        try:
            response = requests.post(self.base_url, headers=headers, json=data)
            response_data = response.json()
            
            if response.status_code == 200:
                advice = response_data['choices'][0]['message']['content']
                self.history.append({
                    "request": prompt,
                    "response": advice,
                    "timestamp": datetime.datetime.now().isoformat()
                })
                return advice
            else:
                return f"API错误: {response.status_code} - {response_data.get('error', {}).get('message', '未知错误')}"
        except Exception as e:
            return f"请求失败: {str(e)}"

# 主应用程序
class EcoGuardianApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("EcoGuardian - 生态系统监测与预测平台")
        self.setGeometry(100, 100, 1400, 900)
        
        # 设置应用样式
        self.setStyle()
        
        # 初始化变量
        self.current_params = EnvironmentParameters()
        self.current_results = {}
        self.simulation_history = []
        self.ai_assistant = AIAssistant()
        
        # 创建UI
        self.init_ui()
        
        # 加载上次的会话
        self.load_last_session()
    
    def setStyle(self):
        # 设置全局样式
        app.setStyle(QStyleFactory.create("Fusion"))
        
        # 自定义调色板
        palette = QPalette()
        palette.setColor(QPalette.ColorRole.Window, QColor(240, 245, 240))
        palette.setColor(QPalette.ColorRole.WindowText, QColor(0, 70, 0))
        palette.setColor(QPalette.ColorRole.Base, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.AlternateBase, QColor(230, 240, 230))
        palette.setColor(QPalette.ColorRole.ToolTipBase, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.ToolTipText, QColor(0, 70, 0))
        palette.setColor(QPalette.ColorRole.Text, QColor(0, 30, 0))
        palette.setColor(QPalette.ColorRole.Button, QColor(100, 160, 100))
        palette.setColor(QPalette.ColorRole.ButtonText, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.BrightText, QColor(255, 255, 255))
        palette.setColor(QPalette.ColorRole.Highlight, QColor(60, 140, 60))
        palette.setColor(QPalette.ColorRole.HighlightedText, QColor(255, 255, 255))
        app.setPalette(palette)
        
        # 设置字体
        font = QFont("Microsoft YaHei UI", 9)
        app.setFont(font)
    
    def init_ui(self):
        # 创建主布局
        main_widget = QWidget()
        main_layout = QHBoxLayout(main_widget)
        
        # 左侧面板 - 参数输入
        left_panel = QWidget()
        left_panel.setMinimumWidth(350)
        left_panel.setMaximumWidth(450)
        left_layout = QVBoxLayout(left_panel)
        
        # 模拟信息组
        sim_info_group = QGroupBox("模拟信息")
        sim_info_layout = QGridLayout(sim_info_group)
        
        self.sim_type_combo = QComboBox()
        self.sim_type_combo.addItems(["森林火灾预测"])
        self.sim_type_combo.currentIndexChanged.connect(self.on_sim_type_changed)
        sim_info_layout.addWidget(QLabel("模拟类型:"), 0, 0)
        sim_info_layout.addWidget(self.sim_type_combo, 0, 1)
        
        self.sim_name_edit = QLineEdit("我的模拟")
        sim_info_layout.addWidget(QLabel("模拟名称:"), 1, 0)
        sim_info_layout.addWidget(self.sim_name_edit, 1, 1)
        
        self.sim_desc_edit = QTextEdit()
        self.sim_desc_edit.setMaximumHeight(60)
        self.sim_desc_edit.setPlaceholderText("输入模拟描述...")
        sim_info_layout.addWidget(QLabel("描述:"), 2, 0)
        sim_info_layout.addWidget(self.sim_desc_edit, 2, 1)
        
        left_layout.addWidget(sim_info_group)
        
        # 参数输入组
        self.params_group = QGroupBox("环境参数")
        self.params_layout = QGridLayout(self.params_group)
        self.create_parameter_inputs()
        left_layout.addWidget(self.params_group)
        
        # 控制按钮
        control_layout = QHBoxLayout()
        
        self.run_btn = QPushButton("运行模拟")
        self.run_btn.setIcon(QIcon.fromTheme("media-playback-start"))
        self.run_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; padding: 8px;")
        self.run_btn.clicked.connect(self.run_simulation)
        control_layout.addWidget(self.run_btn)
        
        self.save_btn = QPushButton("保存结果")
        self.save_btn.setIcon(QIcon.fromTheme("document-save"))
        self.save_btn.clicked.connect(self.save_results)
        control_layout.addWidget(self.save_btn)
        
        left_layout.addLayout(control_layout)
        
        # 历史记录
        history_group = QGroupBox("历史模拟")
        history_layout = QVBoxLayout(history_group)
        
        self.history_list = QListWidget()
        self.history_list.itemDoubleClicked.connect(self.load_history_item)
        history_layout.addWidget(self.history_list)
        
        left_layout.addWidget(history_group)
        
        # 右侧面板 - 结果展示
        right_panel = QWidget()
        right_layout = QVBoxLayout(right_panel)
        
        # 结果标签
        self.result_label = QLabel("等待模拟运行...")
        self.result_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.result_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #2E7D32;")
        right_layout.addWidget(self.result_label)
        
        # 标签页
        self.tabs = QTabWidget()
        
        # 3D可视化标签页
        tab_3d = QWidget()
        layout_3d = QVBoxLayout(tab_3d)
        self.canvas_3d = ThreeDCanvas(tab_3d, width=8, height=6, dpi=100)
        layout_3d.addWidget(self.canvas_3d)
        self.tabs.addTab(tab_3d, "3D 可视化")
        
        # 2D可视化标签页
        tab_2d = QWidget()
        layout_2d = QVBoxLayout(tab_2d)
        self.canvas_2d = TwoDCanvas(tab_2d, width=8, height=6, dpi=100)
        layout_2d.addWidget(self.canvas_2d)
        self.tabs.addTab(tab_2d, "2D 地图")
        
        # 结果详情标签页
        tab_details = QWidget()
        layout_details = QVBoxLayout(tab_details)
        
        self.result_text = QTextEdit()
        self.result_text.setReadOnly(True)
        layout_details.addWidget(self.result_text)
        
        self.tabs.addTab(tab_details, "结果详情")
        
        # AI建议标签页
        tab_ai = QWidget()
        layout_ai = QVBoxLayout(tab_ai)
        
        ai_header = QWidget()
        ai_header_layout = QHBoxLayout(ai_header)
        
        self.ai_key_edit = QLineEdit()
        self.ai_key_edit.setPlaceholderText("输入DeepSeek API密钥...")
        ai_header_layout.addWidget(QLabel("API密钥:"))
        ai_header_layout.addWidget(self.ai_key_edit)
        
        self.get_advice_btn = QPushButton("获取AI建议")
        self.get_advice_btn.setIcon(QIcon.fromTheme("emblem-favorite"))
        self.get_advice_btn.clicked.connect(self.get_ai_advice)
        ai_header_layout.addWidget(self.get_advice_btn)
        
        layout_ai.addWidget(ai_header)
        
        self.ai_advice_text = QTextEdit()
        self.ai_advice_text.setReadOnly(True)
        self.ai_advice_text.setPlaceholderText("AI建议将显示在这里...")
        layout_ai.addWidget(self.ai_advice_text)
        
        
        right_layout.addWidget(self.tabs)
        
        # 状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_label = QLabel("就绪")
        self.status_bar.addWidget(self.status_label)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        self.status_bar.addPermanentWidget(self.progress_bar)
        
        # 添加左右面板到主布局
        splitter = QSplitter(Qt.Orientation.Horizontal)
        splitter.addWidget(left_panel)
        splitter.addWidget(right_panel)
        splitter.setSizes([350, 1050])
        
        main_layout.addWidget(splitter)
        self.setCentralWidget(main_widget)
    
    def create_parameter_inputs(self):
        # 清除现有参数
        for i in reversed(range(self.params_layout.count())): 
            widget = self.params_layout.itemAt(i).widget()
            if widget is not None:
                widget.setParent(None)
        
        # 添加参数输入字段
        params = self.current_params.params
        row = 0
        
        # 通用参数
        self.add_parameter_input("温度 (°C):", "temperature", params['temperature'], row)
        row += 1
        self.add_parameter_input("湿度 (%):", "humidity", params['humidity'], row)
        row += 1
        self.add_parameter_input("降水量 (mm):", "precipitation", params['precipitation'], row)
        row += 1
        
        if self.current_params.simulation_type == "wildfire":
            # 火灾特定参数
            self.add_parameter_input("风速 (m/s):", "wind_speed", params['wind_speed'], row)
            row += 1
            self.add_parameter_input("风向 (度):", "wind_direction", params['wind_direction'], row)
            row += 1
            self.add_parameter_input("植被密度:", "vegetation_density", params['vegetation_density'], row)
            row += 1
            self.add_parameter_input("地形坡度 (度):", "terrain_slope", params['terrain_slope'], row)
            row += 1
            self.add_parameter_input("坡向 (度):", "terrain_aspect", params['terrain_aspect'], row)
            row += 1
            self.add_parameter_input("高程 (m):", "elevation", params['elevation'], row)
            row += 1
            self.add_parameter_input("可燃物载量:", "fuel_load", params['fuel_load'], row)
            row += 1
            self.add_parameter_input("太阳辐射 (W/m²):", "solar_radiation", params['solar_radiation'], row)
            row += 1
            self.add_parameter_input("林冠覆盖率 (%):", "canopy_cover", params['canopy_cover'], row)
            row += 1
            self.add_parameter_input("可燃物湿度 (%):", "fuel_moisture", params['fuel_moisture'], row)
            row += 1
            self.add_parameter_input("历史火灾频率:", "fire_history", params['fire_history'], row)
            row += 1
            self.add_parameter_input("人类活动指数:", "human_activity", params['human_activity'], row)
        else:
            # 洪水/干旱特定参数
            self.add_parameter_input("蒸发率 (mm/天):", "evaporation_rate", params['evaporation_rate'], row)
            row += 1
            self.add_parameter_input("土壤湿度 (%):", "soil_moisture", params['soil_moisture'], row)
            row += 1
            self.add_parameter_input("地形高程 (m):", "terrain_elevation", params['terrain_elevation'], row)
            row += 1
            self.add_parameter_input("植被覆盖率 (%):", "vegetation_coverage", params['vegetation_coverage'], row)
            row += 1
            self.add_parameter_input("河流流量 (m³/s):", "river_discharge", params['river_discharge'], row)
            row += 1
            self.add_parameter_input("雪水当量 (mm):", "snow_water_equivalent", params['snow_water_equivalent'], row)
            row += 1
            self.add_parameter_input("地下水位 (m):", "groundwater_level", params['groundwater_level'], row)
            row += 1
            self.add_parameter_input("排水能力 (mm/h):", "drainage_capacity", params['drainage_capacity'], row)
            row += 1
            self.add_parameter_input("不透水表面 (%):", "impervious_surface", params['impervious_surface'], row)
            row += 1
            self.add_parameter_input("集水区面积 (km²):", "catchment_area", params['catchment_area'], row)
    
    def add_parameter_input(self, label, param_name, value, row):
        label_widget = QLabel(label)
        input_widget = QLineEdit(str(value))
        input_widget.setProperty("param_name", param_name)
        input_widget.textChanged.connect(self.update_parameter)
        
        self.params_layout.addWidget(label_widget, row, 0)
        self.params_layout.addWidget(input_widget, row, 1)
    
    def update_parameter(self):
        sender = self.sender()
        if sender:
            param_name = sender.property("param_name")
            try:
                value = float(sender.text())
                self.current_params.params[param_name] = value
            except ValueError:
                pass
    
    def on_sim_type_changed(self, index):
        self.current_params.simulation_type = "wildfire" if index == 0 else "flood"
        self.create_parameter_inputs()
    
    def run_simulation(self):
        # 更新模拟信息
        self.current_params.name = self.sim_name_edit.text()
        self.current_params.description = self.sim_desc_edit.toPlainText()
        self.current_params.uuid = str(uuid.uuid4())
        self.current_params.timestamp = datetime.datetime.now().isoformat()
        
        # 显示进度
        self.progress_bar.setVisible(True)
        self.progress_bar.setRange(0, 0)  # 不确定进度
        self.status_label.setText("正在运行模拟...")
        QApplication.processEvents()
        
        # 运行模拟
        try:
            if self.current_params.simulation_type == "wildfire":
                model = ForestFireModel(self.current_params.params)
                results = model.calculate()
                self.current_results = results
                
                # 更新结果标签
                risk_level = results['risk_level']
                risk_value = results['overall_risk']
                self.result_label.setText(
                    f"火灾风险: {risk_value:.2f} ({risk_level}) | "
                    f"蔓延概率: {results['spread_probability']:.2f} | "
                    f"关键区域: {len(results['critical_zones'])}个"
                )
                
                # 更新可视化
                terrain = np.array(results['terrain'])
                risk_map = np.array(results['risk_map'])
                self.canvas_3d.plot_terrain(terrain, risk_map, "wildfire")
                self.canvas_2d.plot_map(risk_map, "wildfire", "火灾风险")
                
                # 更新结果详情
                details = (
                    f"模拟名称: {self.current_params.name}\n"
                    f"模拟类型: 森林火灾预测\n"
                    f"模拟时间: {self.current_params.timestamp}\n"
                    f"模拟ID: {self.current_params.uuid}\n\n"
                    f"综合风险指数: {risk_value:.4f}\n"
                    f"风险等级: {risk_level}\n"
                    f"火势蔓延概率: {results['spread_probability']:.4f}\n"
                    f"关键区域数量: {len(results['critical_zones'])}\n\n"
                    "主要环境参数:\n"
                    f"  温度: {self.current_params.params['temperature']}°C\n"
                    f"  湿度: {self.current_params.params['humidity']}%\n"
                    f"  风速: {self.current_params.params['wind_speed']}m/s\n"
                    f"  植被密度: {self.current_params.params['vegetation_density']:.2f}\n"
                    f"  可燃物载量: {self.current_params.params['fuel_load']:.2f}\n"
                )
                self.result_text.setText(details)
                
            else:
                model = FloodDroughtModel(self.current_params.params)
                results = model.calculate()
                self.current_results = results
                
                # 更新结果标签
                self.result_label.setText(
                    f"洪水风险: {results['flood_risk']:.2f} ({results['flood_level']}) | "
                    f"干旱风险: {results['drought_risk']:.2f} ({results['drought_level']}) | "
                    f"水平衡: {results['water_balance']:.2f} m³"
                )
                
                # 更新可视化
                terrain = np.array(results['terrain'])
                flood_map = np.array(results['flood_map'])
                drought_map = np.array(results['drought_map'])
                self.canvas_3d.plot_terrain(terrain, flood_map, "flood")
                self.canvas_2d.plot_map((flood_map, drought_map), "flood", "洪水与干旱风险")
                
                # 更新结果详情
                details = (
                    f"模拟名称: {self.current_params.name}\n"
                    f"模拟类型: 洪水/干旱预测\n"
                    f"模拟时间: {self.current_params.timestamp}\n"
                    f"模拟ID: {self.current_params.uuid}\n\n"
                    f"洪水风险: {results['flood_risk']:.4f} ({results['flood_level']})\n"
                    f"干旱风险: {results['drought_risk']:.4f} ({results['drought_level']})\n"
                    f"水平衡: {results['water_balance']:.2f} m³\n"
                    f"洪水区域: {len(results['flood_zones'])}\n"
                    f"干旱区域: {len(results['drought_zones'])}\n\n"
                    "主要环境参数:\n"
                    f"  降水量: {self.current_params.params['precipitation']}mm\n"
                    f"  温度: {self.current_params.params['temperature']}°C\n"
                    f"  蒸发率: {self.current_params.params['evaporation_rate']}mm/天\n"
                    f"  河流流量: {self.current_params.params['river_discharge']}m³/s\n"
                    f"  集水区面积: {self.current_params.params['catchment_area']}km²\n"
                )
                self.result_text.setText(details)
            
            # 添加到历史记录
            self.add_to_history()
            self.status_label.setText("模拟完成！")
            
        except Exception as e:
            QMessageBox.critical(self, "错误", f"模拟运行时出错:\n{str(e)}")
            self.status_label.setText(f"错误: {str(e)}")
        
        # 隐藏进度条
        self.progress_bar.setVisible(False)
    
    def add_to_history(self):
        # 添加到历史列表
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
        item_text = f"{timestamp} - {self.current_params.name} ({'火灾' if self.current_params.simulation_type == 'wildfire' else '洪水'})"
        self.history_list.insertItem(0, item_text)
        
        # 保存到历史记录
        history_item = {
            "params": self.current_params.to_dict(),
            "results": self.current_results,
            "timestamp": timestamp
        }
        self.simulation_history.insert(0, history_item)
        
        # 保存会话
        self.save_session()
    
    def load_history_item(self, item):
        index = self.history_list.row(item)
        if 0 <= index < len(self.simulation_history):
            history_item = self.simulation_history[index]
            
            # 加载参数
            self.current_params.from_dict(history_item["params"])
            self.current_results = history_item["results"]
            
            # 更新UI
            self.sim_name_edit.setText(self.current_params.name)
            self.sim_desc_edit.setText(self.current_params.description)
            
            sim_type_index = 0 if self.current_params.simulation_type == "wildfire" else 1
            self.sim_type_combo.setCurrentIndex(sim_type_index)
            
            # 更新参数输入
            self.create_parameter_inputs()
            
            # 更新结果
            if self.current_params.simulation_type == "wildfire":
                # 更新结果标签
                risk_level = self.current_results['risk_level']
                risk_value = self.current_results['overall_risk']
                self.result_label.setText(
                    f"火灾风险: {risk_value:.2f} ({risk_level}) | "
                    f"蔓延概率: {self.current_results['spread_probability']:.2f} | "
                    f"关键区域: {len(self.current_results['critical_zones'])}个"
                )
                
                # 更新可视化
                terrain = np.array(self.current_results['terrain'])
                risk_map = np.array(self.current_results['risk_map'])
                self.canvas_3d.plot_terrain(terrain, risk_map, "wildfire")
                self.canvas_2d.plot_map(risk_map, "wildfire", "火灾风险")
                
                # 更新结果详情
                details = (
                    f"模拟名称: {self.current_params.name}\n"
                    f"模拟类型: 森林火灾预测\n"
                    f"模拟时间: {self.current_params.timestamp}\n"
                    f"模拟ID: {self.current_params.uuid}\n\n"
                    f"综合风险指数: {risk_value:.4f}\n"
                    f"风险等级: {risk_level}\n"
                    f"火势蔓延概率: {self.current_results['spread_probability']:.4f}\n"
                    f"关键区域数量: {len(self.current_results['critical_zones'])}\n\n"
                    "主要环境参数:\n"
                    f"  温度: {self.current_params.params['temperature']}°C\n"
                    f"  湿度: {self.current_params.params['humidity']}%\n"
                    f"  风速: {self.current_params.params['wind_speed']}m/s\n"
                    f"  植被密度: {self.current_params.params['vegetation_density']:.2f}\n"
                    f"  可燃物载量: {self.current_params.params['fuel_load']:.2f}\n"
                )
                self.result_text.setText(details)
                
            else:
                # 更新结果标签
                self.result_label.setText(
                    f"洪水风险: {self.current_results['flood_risk']:.2f} ({self.current_results['flood_level']}) | "
                    f"干旱风险: {self.current_results['drought_risk']:.2f} ({self.current_results['drought_level']}) | "
                    f"水平衡: {self.current_results['water_balance']:.2f} m³"
                )
                
                # 更新可视化
                terrain = np.array(self.current_results['terrain'])
                flood_map = np.array(self.current_results['flood_map'])
                drought_map = np.array(self.current_results['drought_map'])
                self.canvas_3d.plot_terrain(terrain, flood_map, "flood")
                self.canvas_2d.plot_map((flood_map, drought_map), "flood", "洪水与干旱风险")
                
                # 更新结果详情
                details = (
                    f"模拟名称: {self.current_params.name}\n"
                    f"模拟类型: 洪水/干旱预测\n"
                    f"模拟时间: {self.current_params.timestamp}\n"
                    f"模拟ID: {self.current_params.uuid}\n\n"
                    f"洪水风险: {self.current_results['flood_risk']:.4f} ({self.current_results['flood_level']})\n"
                    f"干旱风险: {self.current_results['drought_risk']:.4f} ({self.current_results['drought_level']})\n"
                    f"水平衡: {self.current_results['water_balance']:.2f} m³\n"
                    f"洪水区域: {len(self.current_results['flood_zones'])}\n"
                    f"干旱区域: {len(self.current_results['drought_zones'])}\n\n"
                    "主要环境参数:\n"
                    f"  降水量: {self.current_params.params['precipitation']}mm\n"
                    f"  温度: {self.current_params.params['temperature']}°C\n"
                    f"  蒸发率: {self.current_params.params['evaporation_rate']}mm/天\n"
                    f"  河流流量: {self.current_params.params['river_discharge']}m³/s\n"
                    f"  集水区面积: {self.current_params.params['catchment_area']}km²\n"
                )
                self.result_text.setText(details)
            
            self.status_label.setText(f"已加载历史模拟: {self.current_params.name}")
    
    def get_ai_advice(self):
        api_key = self.ai_key_edit.text().strip()
        if not api_key:
            QMessageBox.warning(self, "警告", "请输入DeepSeek API密钥")
            return
        
        self.ai_assistant.api_key = api_key
        
        # 准备数据
        params_data = self.current_params.to_dict()
        results_data = self.current_results
        
        # 显示进度
        self.progress_bar.setVisible(True)
        self.progress_bar.setRange(0, 0)
        self.status_label.setText("正在获取AI建议...")
        self.ai_advice_text.setPlainText("正在获取AI建议，请稍候...")
        QApplication.processEvents()
        
        try:
            advice = self.ai_assistant.get_advice(params_data, results_data)
            self.ai_advice_text.setPlainText(advice)
            self.status_label.setText("AI建议获取成功！")
        except Exception as e:
            self.ai_advice_text.setPlainText(f"获取AI建议时出错:\n{str(e)}")
            self.status_label.setText(f"错误: {str(e)}")
        
        self.progress_bar.setVisible(False)
    
    def save_results(self):
        if not self.current_results:
            QMessageBox.warning(self, "警告", "没有可保存的结果，请先运行模拟")
            return
        
        # 生成文件名
        timestamp = datetime.datetime.now().strftime("%y%m%d")
        image_filename = f"IMAGE_{timestamp}_01.png"
        data_filename = f"DATA_{timestamp}_01.json"
        
        # 创建目录
        os.makedirs("images", exist_ok=True)
        os.makedirs("json", exist_ok=True)
        
        try:
            # 保存图像
            image_path = os.path.join("images", image_filename)
            
            if self.current_params.simulation_type == "wildfire":
                self.canvas_2d.save_image(image_path)
            else:
                self.canvas_3d.save_image(image_path)
            
            # 保存数据
            data_path = os.path.join("json", data_filename)
            save_data = {
                "parameters": self.current_params.to_dict(),
                "results": self.current_results,
                "image_file": image_filename
            }
            
            with open(data_path, "w") as f:
                json.dump(save_data, f, indent=2)
            
            QMessageBox.information(self, "保存成功", 
                                  f"结果已保存:\n图像: {image_path}\n数据: {data_path}")
            self.status_label.setText(f"结果已保存到 {image_path} 和 {data_path}")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"保存结果时出错:\n{str(e)}")
            self.status_label.setText(f"保存错误: {str(e)}")
    
    def save_session(self):
        session_data = {
            "history": self.simulation_history,
            "last_params": self.current_params.to_dict(),
            "last_sim_type": self.sim_type_combo.currentIndex()
        }
        
        try:
            with open("ecoguardian_session.json", "w") as f:
                json.dump(session_data, f, indent=2)
        except Exception as e:
            print(f"保存会话时出错: {str(e)}")
    
    def load_last_session(self):
        try:
            if os.path.exists("ecoguardian_session.json"):
                with open("ecoguardian_session.json", "r") as f:
                    session_data = json.load(f)
                
                self.simulation_history = session_data.get("history", [])
                
                # 加载历史记录到列表
                for item in reversed(self.simulation_history):
                    timestamp = item["timestamp"]
                    name = item["params"]["name"]
                    sim_type = "火灾" if item["params"]["simulation_type"] == "wildfire" else "洪水"
                    self.history_list.addItem(f"{timestamp} - {name} ({sim_type})")
                
                # 加载上次的参数
                last_params = session_data.get("last_params")
                if last_params:
                    self.current_params.from_dict(last_params)
                    self.sim_name_edit.setText(self.current_params.name)
                    self.sim_desc_edit.setText(self.current_params.description)
                    self.sim_type_combo.setCurrentIndex(session_data.get("last_sim_type", 0))
                    self.create_parameter_inputs()
                
                self.status_label.setText(f"已加载 {len(self.simulation_history)} 条历史记录")
        except Exception as e:
            print(f"加载会话时出错: {str(e)}")
    
    def closeEvent(self, event):
        self.save_session()
        event.accept()

# 运行应用程序
if __name__ == "__main__":
    app = QApplication(sys.argv)
    
    # 设置应用程序图标
    if hasattr(QStyleFactory, "setStyle"):
        app.setStyle("Fusion")
    
    # 创建主窗口
    window = EcoGuardianApp()
    window.show()
    
    # 启动应用程序
    sys.exit(app.exec())